package com.huawei.bitfun;

import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.huawei.bitfun.insight.InsightExContext;
import com.huawei.bitfun.insight.InsightExMappingRegistryManager;
import com.huawei.bitfun.insight.InsightExRequestDispatcher;
import com.huawei.bitfun.insight.InsightExRequestHandler;
import com.huawei.bitfun.insight.utils.Common;
import com.huawei.deveco.insight.ohos.common.ProfilerError;
import com.huawei.deveco.insight.ohos.common.Response;
import com.huawei.deveco.insight.ohos.model.dto.JcefRequest;
import com.huawei.deveco.insight.ohos.utils.DocumentUtils;
import com.huawei.deveco.insight.ohos.utils.JsonUtil;
import com.huawei.deveco.insight.ohos.utils.ValidateUtil;
import com.intellij.ide.ui.LafManagerListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowFactory;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.jcef.JBCefBrowser;
import com.intellij.util.ui.UIUtil;
import org.apache.commons.io.FileUtils;
import org.cef.browser.CefBrowser;
import org.cef.browser.CefFrame;
import org.cef.browser.CefMessageRouter;
import org.cef.callback.CefQueryCallback;
import org.cef.handler.CefMessageRouterHandlerAdapter;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;

public class InsightExWindowsFactory implements ToolWindowFactory {
    private static final String RESOURCE_DB_FILE_PATH = Common.joinWithForwardSlash("db", "profilerExSql.db");

    private static final Logger LOGGER = LoggerFactory.getLogger(InsightExWindowsFactory.class);

    @Override
    public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
        InsightExContext.setProject(project);
        initDataBase();
        JBCefBrowser browser = JBCefBrowser.createBuilder()
                .setOffScreenRendering(false).setUrl(Common.FRONTEND_URL).build();
        // 添加消息路由
        addMessageRouter(browser);
        // 添加主题监听
        addThemeChangeListener(browser);
        browser.getJBCefClient().addRequestHandler(new InsightExRequestHandler(), browser.getCefBrowser());

        InsightExMappingRegistryManager.getInstance().loadRequestMapping();
        ContentFactory contentFactory = ContentFactory.getInstance();
        Content content = contentFactory.createContent(browser.getComponent(), "", false);
        toolWindow.getContentManager().addContent(content);
    }

    private void initDataBase() {
        String insightExDbFilePath = Common.getInsightExDbFilePath();
        if (FileUtils.getFile(insightExDbFilePath).exists()) {
            return;
        }
        DocumentUtils.createIfAbsent(Common.getCacheDBPath());
        try(InputStream inputStream = getClass().getClassLoader().getResourceAsStream(RESOURCE_DB_FILE_PATH)) {
            if (inputStream == null) {
                LOGGER.warn("resource not found: {}", RESOURCE_DB_FILE_PATH);
                return;
            }
            Files.copy(inputStream, Path.of(insightExDbFilePath));
        } catch (IOException e) {
            LOGGER.warn("insight ex start up error.", e);
        }
    }

    private void addThemeChangeListener(JBCefBrowser browser) {
        ApplicationManager.getApplication().getMessageBus().connect().subscribe(
                LafManagerListener.TOPIC, (LafManagerListener) event -> {
                    String command = "window.setTheme("+ UIUtil.isUnderDarcula() +");";
                    Optional.ofNullable(browser).map(JBCefBrowser::getCefBrowser)
                            .ifPresent(cefBrowser -> {cefBrowser.executeJavaScript(command, cefBrowser.getURL(), 0);});
                }
        );
    }
    private void addMessageRouter(JBCefBrowser browser) {
        CefMessageRouter router = CefMessageRouter.create();
        router.addHandler(new CefMessageRouterHandlerAdapter() {
            @Override
            public boolean onQuery(CefBrowser browser, CefFrame frame, long queryId, String request, boolean persistent, CefQueryCallback callback) {
                JcefRequest jcefRequest = JsonUtil.parseObject(request, JcefRequest.class);
                ValidateUtil.validate(jcefRequest);
                String requestKey = jcefRequest.getKey();
                String requestMethod = jcefRequest.getData().getMethod();
                JSONObject params = jcefRequest.getData().getParams();
                ApplicationManager.getApplication().executeOnPooledThread(() -> {
                    try {
                        Response<?> response = InsightExRequestDispatcher.getInstance()
                                .dispatch(List.of(requestKey, requestMethod), params);
                        if (response.isNeedCallback()) {
                            callback.success(new Gson().toJson(response));
                        }
                    } catch (Exception e) {
                        callback.failure(ProfilerError.PERSISTENCE_ERROR.getCode(),
                                new Gson().toJson(Response.failure(ProfilerError.PERSISTENCE_ERROR)));
                    }
                });
                return true;
            }
        }, true);
        browser.getJBCefClient().getCefClient().addMessageRouter(router);
    }
}
